package main.java.com.lee.practise;

import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

/**
 * @Description TODO
 * @Author winston
 * @DateTime 2022/2/28
 */
public class SimpleProCons<T> {
    private final List<T> list = new LinkedList<>();
    private Integer max = 100;

    /**
     * 用来控制队列的添加, 移除, 数量统计操作, 保证线程安全.
     */
    private Object LOCK_OBJECT = new Object();

    /**
     * 在添加元素时, 判断元素数量是否已满, 满就阻塞在NOT_FULL的await方法上.
     * 在添加操作执行完成后, 通知阻塞在not_empty上的线程, 可以提取元素了.
     */
    private Object NOT_FULL = new Object();

    /**
     * 获取元素时, 判断队列是否为空, 如果为空, 就阻塞NOT_EMPTY上, 等待添加完元素后唤醒.
     * 在移除完后, 通知not_full线程, 可以执行添加才做了
     */
    private Object NOT_EMPTY = new Object();

    private Integer size = 0;

    public void add(T t) throws InterruptedException {
        while (size >= max) {
            synchronized (NOT_FULL) {
                System.out.println("队列已满");
                NOT_FULL.wait();
            }
        }
        synchronized (LOCK_OBJECT) {
            list.add(t);
            size += 1;
//            Thread.sleep(1000);
        }

        synchronized (NOT_EMPTY) {
            NOT_EMPTY.notify();
        }
    }

    public T remove() throws InterruptedException {
        T t1 = null;
        while (size <= 0) {
            synchronized (NOT_EMPTY) {
                System.out.println("队列中没有元素");
                NOT_EMPTY.wait();
            }
        }
        synchronized (LOCK_OBJECT) {
            t1 = list.remove(0);
            size -= 1;
        }

        synchronized (NOT_FULL) {
            NOT_FULL.notify();
        }
        System.out.println(t1);
        return t1;
    }

    public static void main(String[] args) throws InterruptedException {
        SimpleProCons<Integer> proCons = new SimpleProCons<>();
        ExecutorService pro = Executors.newFixedThreadPool(5);
        ExecutorService cons = Executors.newFixedThreadPool(5);
        IntStream.rangeClosed(1, 10).forEach(i->{
            pro.submit(()-> {
                try {
                    proCons.add(i);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        });

        IntStream.rangeClosed(1, 10).forEach(i->{
            cons.submit(()-> {
                try {
                    proCons.remove();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        });
        cons.shutdown();
        while (!cons.isTerminated()) {
//            System.out.println("未执行完成");
        }
        System.out.println("执行完毕");
    }


}
